0%

cypher与sql对比

cypher与sql对比

以学生选课场景为例来进行对比

背景说明
假设我们有一个高校教务系统,包含以下实体:

  • 学生(Student):有学号、姓名
  • 课程(Course):有课程编号、课程名、学分
  • 选课关系(Enroll):学生选了某门课,可能包含成绩(grade)

在关系型数据库中,这通常用三张表实现;在 Neo4j 中,则用节点和关系直接建模。


索引(Index)

索引用于加速查找起点(如按学号找学生、按课程名找课)。

SQL Cypher
CREATE INDEX idx_student_id ON students (student_id);
CREATE INDEX idx_course_name ON courses (course_name);
CREATE INDEX Student_studentId IF NOT EXISTS FOR (s:Student) ON s.studentId;
CREATE INDEX Course_courseName IF NOT EXISTS FOR (c:Course) ON c.courseName;

💡 注意:Neo4j 的索引只用于 MATCH 的起点(如 (s:Student {studentId: '2023001'})),后续遍历靠图结构,无需 JOIN。


查询示例

1. 选择并返回所有记录

SQL Cypher
SELECT * FROM students; MATCH (s:Student) RETURN s;

2. 返回特定字段、排序与分页

需求:列出学分最高的前 5 门课程。

SQL Cypher
SELECT course_name, credits FROM courses ORDER BY credits DESC LIMIT 5; MATCH (c:Course) RETURN c.courseName, c.credits ORDER BY c.credits DESC LIMIT 5;

3. 按名称查找单门课程

需求:查找课程名为 “数据库原理” 的课程信息。

SQL Cypher
SELECT course_name, credits FROM courses WHERE course_name = ‘数据库原理’; MATCH (c:Course {courseName: ‘数据库原理’}) RETURN c.courseName, c.credits;

更简洁:属性直接写在 {} 中,无需 WHERE


4. 按列表筛选课程

需求:查找 “高等数学” 和 “线性代数” 两门课的信息。

SQL Cypher
SELECT course_name, credits FROM courses WHERE course_name IN (‘高等数学’, ‘线性代数’); MATCH (c:Course) WHERE c.courseName IN [‘高等数学’, ‘线性代数’] RETURN c.courseName, c.credits;

5. 多条件筛选

需求:查找课程名以 “数据” 开头 且 学分 ≥ 3 的课程。

SQL Cypher
SELECT course_name, credits FROM courses WHERE course_name LIKE ‘数据%’ AND credits >= 3; MATCH (c:Course) WHERE c.courseName STARTS WITH ‘数据’ AND c.credits >= 3 RETURN c.courseName, c.credits;

💡 Neo4j 用 STARTS WITH / CONTAINS / ENDS WITH 替代 LIKE,更直观。


6. 连接学生与课程

需求:找出选了 “数据库原理” 的所有学生姓名。

SQL(需要多次 JOIN)
1
2
3
4
5
SELECT DISTINCT s.name
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
JOIN courses c ON e.course_id = c.course_id
WHERE c.course_name = '数据库原理';
Cypher(直接走关系)
1
2
MATCH (c:Course {courseName: '数据库原理'}) <-[:ENROLL]- (s:Student)
RETURN DISTINCT s.name;

无需 JOIN!关系本身就是路径
关系类型 :ENROLL 直接表达了“学生选课”的语义。


7. 聚合:每门课的选课人数

需求:统计每门课程有多少人选,按人数降序,取前 3。

SQL Cypher
SELECT c.course_name, COUNT(e.student_id) AS studentCount FROM courses c LEFT JOIN enrollments e ON c.course_id = e.course_id GROUP BY c.course_id, c.course_name ORDER BY studentCount DESC LIMIT 3; MATCH (c:Course) OPTIONAL MATCH (c) <-[:ENROLL]- (s:Student) RETURN c.courseName, COUNT(s) AS studentCount ORDER BY studentCount DESC LIMIT 3;

💡 OPTIONAL MATCH 相当于 LEFT JOIN,确保没被选的课也显示(人数为 0)。


8. 聚合:每个学生的总学分

需求:计算学生 “张三” 已修课程的总学分。

SQL Cypher
SELECT SUM(c.credits) AS totalCredits FROM students s JOIN enrollments e ON s.student_id = e.student_id JOIN courses c ON e.course_id = c.course_id WHERE s.name = ‘张三’; MATCH (s:Student {name: ‘张三’}) -[:ENROLL]-> (c:Course) RETURN sum(c.credits) AS totalCredits;

图遍历天然支持“从学生出发,走到课程,累加学分”。


9. 列出每个学生选的课程(集合聚合)

需求:列出每位学生及其所选课程名(逗号分隔或列表形式)。

SQL Cypher
SELECT s.name, STRING_AGG(c.course_name, ‘, ‘ ORDER BY c.course_name) AS courses FROM students s JOIN enrollments e ON s.student_id = e.student_id JOIN courses c ON e.course_id = c.course_id GROUP BY s.student_id, s.name ORDER BY s.name; MATCH (s:Student) -[:ENROLL]-> (c:Course) RETURN s.name, COLLECT(c.courseName) AS courses ORDER BY s.name;

COLLECT() 自动将多行合并为列表,结果更结构化(适合 JSON 输出)。


总结对比

场景 SQL 特点 Cypher 优势
多表连接 需显式 JOIN,易错、性能差(尤其深度关联) 关系即路径,直接 MATCH (A)-[R]->(B)
聚合分组 必须写 GROUP BY 所有非聚合字段 隐式分组,简洁
返回嵌套结构 需用 STRING_AGG 或应用层处理 内置 COLLECT(),天然支持嵌套
查询可读性 逻辑隐藏在 JOIN 条件中 像画图一样写查询,语义清晰

欢迎关注我的其它发布渠道